﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Domain.EnvDte
{
	using System.Runtime.InteropServices;

	using EnvDTE;

	public class Dte
	{
		const string ProjectGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
		const string SolutionExplorerWindow = "{3AE79031-E1BC-11D0-8F78-00A0C9110057}";
		const string SolutionFolder = "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}";

		readonly EnvDTE.DTE _dte;
		public Dte()
		{
			_dte = (EnvDTE.DTE)Marshal.GetActiveObject("VisualStudio.DTE");

			if (_dte == null) throw new InvalidOperationException("Could not get a DTE");
		}
		public IEnumerable<Command> GetCommands()
		{
			return _dte.Commands.Cast<Command>();
		}

		public IEnumerable<CommandDetail> GetDetailedCommands()
		{
			return _dte.Commands.Cast<Command>().ToArray().Select(c => new CommandDetail(c.LocalizedName, c.ID, ((object[])c.Bindings).Cast<string>().ToArray())).ToArray();

		}

		public object GetDisplay(UIHierarchyItem item)
		{
			object display = item.ToString();
			var comType = ComHelper.GetTypeName(item.Object);
			display = new { ComType = comType, display };
			if (comType == "Project")
			{
				var p = item.Object as Project;

				if (p != null)
					display = new { p.Kind, p.UniqueName, p.FileName, p.FullName, };


			}
			else if (comType == "_UIHierarchyItemMarshaler")
			{
				if (object.ReferenceEquals(item.Object, item))
					return display;
				var uihi = (UIHierarchyItem)item.Object;
				ComHelper.GetTypeName(uihi.Object).Dump("Found child of uihi");
			}
			else
			{
#if LINQPAD
				comType.Dump("Failed to unload");
#endif
			}
			return display;
		}
		public UIHierarchyItem GetSolutionItem()
		{
			_dte.Windows.Item(SolutionExplorerWindow).Activate();
			var uih = _dte.ActiveWindow.Object as UIHierarchy;
			
			var solutionItem = uih.UIHierarchyItems.Cast<UIHierarchyItem>().Single();
			return solutionItem;
		}
		public IEnumerable<UIHierarchyItem> GetChildren(UIHierarchyItem parent)
		{
			var wasExpanded = parent.UIHierarchyItems.Expanded;
			parent.UIHierarchyItems.Expanded = true;
				foreach (var item in parent.UIHierarchyItems.Cast<UIHierarchyItem>().ToArray())
				{
					yield return item;
				}
			parent.UIHierarchyItems.Expanded = wasExpanded;
		}

		public void SuspendResharper()
		{
			try
			{
				_dte.ExecuteCommand("ReSharper_Suspend");
			}
			catch (COMException ex)
			{
				//ex.Dump("Failed to suspend resharper");
			}
		}

		public IEnumerable<UIHierarchyItem> GetDescendants(UIHierarchyItem parent, bool topdown)
		{
			parent.Select(vsUISelectionType.vsUISelectionTypeSelect);
			if (parent.Collection.Count > 0)
				foreach (var item in parent.UIHierarchyItems.Cast<UIHierarchyItem>())
				{//.Where (uihi => uihi.Object is Project))
					if (topdown)
						yield return item;
					foreach (var ic in this.GetDescendants(item, topdown))
						yield return ic;
					if (!topdown)
						yield return item;
				}
		}

		public void UnloadProjects(bool topdown = false)
		{

			_dte.Windows.Item(SolutionExplorerWindow).Activate();
			var uih = _dte.ActiveWindow.Object as UIHierarchy;
			var solutionItem = uih.UIHierarchyItems.Cast<UIHierarchyItem>().Single();
			var failures = new List<object>();
			var unloaded = new List<object>();
			foreach (var uiProject in this.GetDescendants(solutionItem, topdown))
			{
				object display;
				try
				{
					display = GetDisplay(uiProject);
				}
				catch (InvalidCastException)
				{

					continue;
				}

				//var comType = ComHelper.GetTypeName(uiProject.Object);

				uiProject.Select(vsUISelectionType.vsUISelectionTypeSelect);

				try
				{
					_dte.ExecuteCommand("Project.UnloadProject");
					unloaded.Add(display);
				}
				catch (COMException ex)
				{
					if (object.ReferenceEquals(uiProject.Object, uiProject) == false) //assume project is already unloaded
					{
						failures.Add(display);
					}

				}
			}
		}

		public IEnumerable<ProjectInfo> GetProjects(bool topdown = false)
		{
			_dte.Windows.Item(SolutionExplorerWindow).Activate();
			var uih = _dte.ActiveWindow.Object as UIHierarchy;
			var solutionItem = uih.UIHierarchyItems.Cast<UIHierarchyItem>().Single();
			var q = from uiItem in this.GetDescendants(solutionItem, topdown)
					  let project = uiItem.Object as Project
					  where project != null && project.Kind == ProjectGuid
					  select new ProjectInfo(project.FullName, project.FileName, project.UniqueName);

			var items = q.ToArray();
			return items;
		}
		public string GetSlnName()
		{
			return System.IO.Path.GetFileName(_dte.Solution.FullName);
		}
	}
}
